#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
#include"cond.hpp"//包含自己的条件变量
#include"Lock.hpp"//包含自己的锁

using namespace LockModule;

static const int gcap = 10; 
template<class T>
class blockqueue
{
private:
   bool queue_size(){return _q.size()==_cap;}  //是否满
   bool queue_empty(){return _q.empty();}//是否是空的
public:
    blockqueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
    {
    }
    void Equeue(const T& in)//生产者
    {
        LockGuard lockar(_mutex);
        //加锁保护-防止写数据有人来读
       

        //什么时候能放数据什么时候不能放数据，知道吗？生产数据是有条件的
        //结论1：在临界区中等待是必然的（目前）
        while(queue_size())// 5. 对条件进行判断，为了防止伪唤醒，我们通常使用while进行判断！
        {
            std::cout << "生产者进入等待..." << std::endl;

            _cwait_num++;
            //2.等时，释放锁
            _Ccond.wait(_mutex);//wait的时候，必定是持有锁的！！是有问题的！
            _cwait_num--;
            //3.返回，线程被唤醒&&会重新申请锁(它会在临界区醒来！)
            std::cout << "生产者被唤醒..." << std::endl;
        }
        //走到这，上面条件不满足||线程被唤醒
        _q.push(in);                  //生产

        //生产完-判断有没有消费者再等待
        if(_pwait_num)
        {
            std::cout << "叫醒消费者" << std::endl;
            //唤醒消费者
            _Pcond.notify();
        }

        //解锁
    }
    void pop(T* out) //消费者
    {
        //加锁
        LockGuard lockar(_mutex);
        while(queue_empty())//while防止伪唤醒
        {
            _pwait_num++;
            _Pcond.wait(_mutex);//伪唤醒-生产者只发送了一个数据，同时唤醒多个消费者怎么办？
            _pwait_num--;
        }
        //走到这，上面条件不满足||线程被唤醒

        *out = _q.front();//拿数据
        _q.pop();//出队列

        //消费完了，让生产者来生产
        if(_cwait_num)
        {
            //唤醒生产者
            _Ccond.notify();
            //唤醒生产者，生产者会在锁上等待解锁
        }
        //解锁
        //唤醒消费者在锁的后面也是可以的
        //pthread_cond_signal(&_Ccond);
    }
    ~blockqueue()
    {
    }
private:
    std::queue<T> _q;       //保存的数据
    int _cap;               //阻塞队列的最大容量
    Mutex _mutex; //锁--互斥
    cond _Ccond;  //生产者等待的条件变量
    cond _Pcond;  //消费者等待的条件变量

    int _cwait_num;//产生者等待个数
    int _pwait_num;//消费者等待个数
};





// static const int gcap = 10; 
// template<class T>
// class blockqueue
// {
// private:
//    bool queue_size(){return _q.size()==_cap;}  //是否满
//    bool queue_empty(){return _q.empty();}//是否是空的
// public:
//     blockqueue(int cap = gcap):_cap(cap),_cwait_num(0),_pwait_num(0)
//     {
//         //初始化-锁-条件变量
//         pthread_mutex_init(&_mutex,nullptr);//初始化锁
//         pthread_cond_init(&_Ccond,nullptr); //初始化条件变量
//         pthread_cond_init(&_Pcond,nullptr); //初始化条件变量
//     }
//     void Equeue(const T& in)//生产者
//     {
//         //加锁保护-防止写数据有人来读
//         pthread_mutex_lock(&_mutex);  //加锁

//         //什么时候能放数据什么时候不能放数据，知道吗？生产数据是有条件的
//         //结论1：在临界区中等待是必然的（目前）
//         while(queue_size())// 5. 对条件进行判断，为了防止伪唤醒，我们通常使用while进行判断！
//         {
//             std::cout << "生产者进入等待..." << std::endl;

//             _cwait_num++;
//             //2.等时，释放锁
//             pthread_cond_wait(& _Ccond,&_mutex);//wait的时候，必定是持有锁的！！是有问题的！
//             _cwait_num--;
//             //3.返回，线程被唤醒&&会重新申请锁(它会在临界区醒来！)
//             std::cout << "生产者被唤醒..." << std::endl;
//         }
//         //走到这，上面条件不满足||线程被唤醒
//         _q.push(in);                  //生产

//         //生产完-判断有没有消费者再等待
//         if(_pwait_num)
//         {
//             std::cout << "叫醒消费者" << std::endl;
//             //唤醒消费者
//             pthread_cond_signal(&_Pcond);
//         }

//         pthread_mutex_unlock(&_mutex);//解锁
//     }
//     void pop(T* out) //消费者
//     {
//         pthread_mutex_lock(&_mutex);  //加锁
//         while(queue_empty())//while防止伪唤醒
//         {
//             _pwait_num++;
//             pthread_cond_wait(& _Pcond,&_mutex);//伪唤醒-生产者只发送了一个数据，同时唤醒多个消费者怎么办？
//             _pwait_num--;
//         }
//         //走到这，上面条件不满足||线程被唤醒

//         *out = _q.front();//拿数据
//         _q.pop();//出队列

//         //消费完了，让生产者来生产
//         if(_cwait_num)
//         {
//             //唤醒生产者
//             pthread_cond_signal(&_Ccond);
//             //唤醒生产者，生产者会在锁上等待解锁
//         }
//         pthread_mutex_unlock(&_mutex);//解锁
//         //唤醒消费者在锁的后面也是可以的
//         //pthread_cond_signal(&_Ccond);
//     }
//     ~blockqueue()
//     {
//         //销毁锁-条件变量
//         pthread_mutex_destroy(&_mutex);
//         pthread_cond_destroy(&_Ccond);
//         pthread_cond_destroy(&_Pcond);
//     }
// private:
//     std::queue<T> _q;       //保存的数据
//     int _cap;               //阻塞队列的最大容量
//     pthread_mutex_t _mutex; //锁--互斥
//     pthread_cond_t _Ccond;  //生产者等待的条件变量
//     pthread_cond_t _Pcond;  //消费者等待的条件变量

//     int _cwait_num;//产生者等待个数
//     int _pwait_num;//消费者等待个数
// };
